/*
 * User: rant
 * Date: Jul 10, 2007
 *
 *
 */
package laMalinche.editableContext;

import laMalinche.testingPlayGround.testModel.VOEntity;
import laMalinche.rete.nodes.editing.EditableContextReteRoot;

import java.util.*;

/**
 *
 */
public class BasicAboutToChangeManager implements AboutToChangeManager {
	private final List<AboutToChangeListener> aboutToChangeListeners = new ArrayList<AboutToChangeListener>();
	private List<String> aboutToChange = new ArrayList<String>();
	private AboutToChangeManager parent;
    private EditableContextReteRoot reteRoot;
    private List<String> inEditingProcess = new ArrayList<String>();
    private final List<AboutToChangeManager> aboutToChangeManagers = new ArrayList<AboutToChangeManager>();
   private boolean inLoop;

    public void setReteRoot(final EditableContextReteRoot reteRoot) {
		this.reteRoot = reteRoot;
	}

    public void setBecameCertain(final List<String> becameCertain) {
		final Set<String> set = new HashSet<String>(becameCertain);
		removeAboutToChange(set);
	}


	//  inform future editing
	//todo change to set
	public void setInEditingProcess(final List<String> inEditingProcess) {
		List<String> inEditingProcessNew = new ArrayList<String>();
		if (inEditingProcess != null) {
			inEditingProcessNew.addAll(inEditingProcess);
		}
		this.inEditingProcess = inEditingProcessNew;
		final Set<String> inEditingSet = new HashSet<String>(inEditingProcessNew);
		EditableContextReteRoot reteRoot = getReteRoot();
		reteRoot.futureEditingProcess(inEditingSet);
	}

	private EditableContextReteRoot getReteRoot() {
		return reteRoot;
	}

	public void setAboutToChange(List<String> aboutToChange) {
		List<String> aboutToChangeNew = new ArrayList<String>();
		if (aboutToChange != null) {
			aboutToChangeNew.addAll(aboutToChange);
		}
		this.aboutToChange = aboutToChangeNew;
	}

	public void addAboutToChangeManager(AboutToChangeManager aboutToChangeManager) {
		aboutToChangeManager.setParent(this);
		aboutToChangeManagers.add(aboutToChangeManager);
	}

	//TODO return element that can be both field and list
	public Set<String> getAboutToChangeElements() {
		Set<String> aboutToChangeList = new HashSet<String>();
		if (aboutToChange != null) {
			aboutToChangeList.addAll(aboutToChange);
		}
		for (AboutToChangeManager aboutToChange : aboutToChangeManagers) {
			final Set<String> aboutToChangeElements = aboutToChange.getAboutToChangeElements();
			if (aboutToChangeElements != null) {
				aboutToChangeList.addAll(aboutToChangeElements);
			}
		}
		return aboutToChangeList;
	}

	public Set<String> getInEditingProcessElements() {
		Set<String> inEditingList = new HashSet<String>();
		if (inEditingProcess != null) {
			inEditingList.addAll(inEditingProcess);
		}
		for (AboutToChangeManager aboutToChange : aboutToChangeManagers) {
			final Set<String> aboutToChangeElements = aboutToChange.getInEditingProcessElements();
			if (aboutToChangeElements != null) {
				inEditingList.addAll(aboutToChangeElements);
			}
		}
		return inEditingList;
	}

	public void adviseListeners() {
		if (getPartent() != null) {
			((BasicAboutToChangeManager) getPartent()).adviseListeners();
		} else {
			if (aboutToChangeListeners != null && !aboutToChangeListeners.isEmpty()) {
				inLoop = true;
				List<AboutToChangeListener> newListenersList = new ArrayList<AboutToChangeListener>();
				newListenersList.addAll(aboutToChangeListeners);
				CertaintyChangeEvent event = new CertaintyChangeEvent();
				event.setBecameInEditing(getInEditingProcessElements());
				final Iterator<AboutToChangeListener> listIterator = newListenersList.iterator();
				while (inLoop && listIterator.hasNext()) {
					final AboutToChangeListener toChangeListener = listIterator.next();
					toChangeListener.certaintyChange(event);
				}
				inLoop = false;
			}
		}
	}

	public void addAboutToChangeListener(final AboutToChangeListener listener) {
		aboutToChangeListeners.add(listener);
	}

	public boolean isAboutToChange(VOEntity field) {
		return false;
	}

	public void addToAboutToChange(final String derivedFieldOgnl) {
		aboutToChange.add(derivedFieldOgnl);
	}

	public void removeAboutToChange(final String fieldOgnl) {
		if (aboutToChange.contains(fieldOgnl)) {
			aboutToChange.remove(fieldOgnl);
			adviseListeners();
		}
	}


	public void removeAboutToChange(final Set<String> fieldOgnl) {
		if (aboutToChange.containsAll(fieldOgnl)) {
			aboutToChange.removeAll(fieldOgnl);
			adviseListeners();
		}
	}

	AboutToChangeManager getPartent() {
		return parent;
	}

	public void setParent(final AboutToChangeManager parent) {
		this.parent = parent;
	}

	public void addAboutToChange(final String fieldOgnl) {
		if (!aboutToChange.contains(fieldOgnl)) {
			aboutToChange.add(fieldOgnl);
			adviseListeners();
		}
	}

	public void addAboutToChange(final Set<String> fieldOgnl) {
		if (!aboutToChange.containsAll(fieldOgnl)) {
			aboutToChange.addAll(fieldOgnl);
			adviseListeners();
		}
	}
}